﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using eBook.Core.BusinessObjects;
using eBook.Core.Contracts;
using eBook.Entities;
using AutoMapper;
using eBook.Core;


namespace eBook.EFRepositories 
{
  public class LibRepository : ILibRepository
  {
    public boBook GetBookById(int bookId)
    {
      using (eBookLibEntities ctx = new eBookLibEntities())
      {
        var b = ctx.Books.FirstOrDefault( x => x.BookID == bookId);
        return Mapper.Map<boBook>(b);
      }
    }

    public boBook GetBookByISBN(ISBN isbn)
    {
      using ( eBookLibEntities ctx = new eBookLibEntities() )
      {
        var b = this.GetBookEntityByISBN(ctx, isbn);
        return Mapper.Map<boBook>(b);
      }
    }

    public boBook GetBookByISBN(string isbn)
    {
      ISBN n = ISBNFactory.Create(isbn);
      if ( n == null )
        return null;
      
      return this.GetBookByISBN(n);
    }

    private Book GetBookEntityByISBN(eBookLibEntities ctx, ISBN isbn)
    {
      string pivot1 = isbn.ToString();
      string pivot2 = isbn.Transform().ToString();
      var b = ( from x in ctx.Books
                where x.ISBN10 == pivot1 || x.ISBN13 == pivot1
                   || x.ISBN10 == pivot2 || x.ISBN13 == pivot2
                select x ).FirstOrDefault();
      return b;
    }

    public List<boBookListItem> GetBookList()
    {
      using ( eBookLibEntities ctx = new eBookLibEntities() )
      {
        var b = ctx.v_BookInfo.ToList();
        var bo = Mapper.Map<List<boBookListItem>>(b);

        return bo;
      }
    }

    public List<boBook> GetBooksByAuthor(int authorId)
    {
      using (eBookLibEntities ctx = new eBookLibEntities())
      {
        var books = (from x in ctx.BookAuthors
                     where x.AuthorID == authorId
                     select x.Book ).ToList();

        return Mapper.Map< List<boBook> >(books);
      }
    }

    public void SaveOrUpdateBookInfo(boBookInfo info)
    {
      using (eBookLibEntities ctx = new eBookLibEntities())
      {
        DateTime now = DateTime.Now;
        ISBN n = ISBNFactory.Create(info.ISBN10);
        if ( n == null )
          return;

        Book book = this.GetBookEntityByISBN(ctx, n);
        if (book == null)        
        {
          book = new Book{ DateCreated = now };        
          ctx.Books.AddObject(book);
        }
        else
          book.DateModified = now;
        

        book.ASIN = info.ASIN;
        ISBN isbn = null;
        if (!string.IsNullOrEmpty(info.ISBN10))
        {
          isbn = new ISBN10(info.ISBN10);
          book.ISBN10 = isbn.ToString();
          book.ISBN13 = new ISBN13(isbn.Transform()).ToString();
        }
        else
        {
          isbn = new ISBN13(info.ISBN13);
          book.ISBN13 = isbn.ToString();
          book.ISBN10 = new ISBN10(isbn.Transform()).ToString();
        }
        book.DeweyDecimal = info.DeweyDecimal;
        book.LCCN = info.LCCN;

        book.Title = info.Title;
        book.Subtitle = info.Subtitle;

        book.LargeImageURL = info.LargeImageURL;
        book.MediumImageURL = info.MediumImageURL;
        book.SmallImageURL = info.SmallImageURL;

        book.PublicationDate = info.PublicationDate;
        
        int pages = 0;
        if (int.TryParse(info.NumberOfPages, out pages))
          book.NumberOfPages = new int?(pages);

        book.Edition = info.Edition;
        book.EditorialReview = info.EditorialReview;

        #region set links
        
        if (info.Links != null)
        {
          foreach (var item in info.Links)
          {            
            string[] q = item.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            if (q != null && q.Length == 2)
            {
              string linkName = q[0].Trim();
              string linkPath = q[1].Trim();

              if ( book.Links.FirstOrDefault(x => x.Name == linkName ) != null )
                continue;

              Link link = new Link() { DateCreated = now, Book = book };
              link.Name = linkName;
              link.Path = linkPath;
              book.Links.Add(link);
            }
          }
        } 

        #endregion

        #region set publisher
        
        var publisher = ctx.Publishers.FirstOrDefault(x => x.Name == info.PublisherName);
        if (publisher == null)
          publisher = new Publisher() { Name = info.PublisherName };
        book.Publisher = publisher; 

        #endregion

        #region set authors
        
        if (info.Authors != null)
        {
          foreach (var item in info.Authors)
          {
            string authorName = item.Trim();

            var author = ctx.Authors.FirstOrDefault(x => x.Name == authorName);
            if (author == null)
              author = new Author() { Name = authorName };

            ctx.BookAuthors.AddObject(new BookAuthor() { Author = author, Book = book });
          }
        } 

        #endregion

        #region set topics

        if (info.Topics != null)
        {
          foreach (var item in info.Topics)
          {
            var topic = ctx.Topics.FirstOrDefault(x => x.Name == item);
            if (topic == null)
              topic = new Topic() { Name = item };

            ctx.BookTopics.AddObject(new BookTopic() { Topic= topic, Book = book });
          }
        }

        #endregion

        book.Path = info.Path;
        book.FileName = info.FileName;

        ctx.SaveChanges();
      }    
    
    }

    public void SaveOrUpdateBook(boBook book)
    {
      using ( eBookLibEntities ctx = new eBookLibEntities() )
      {
        DateTime now = DateTime.Now;

        Book entity = ctx.Books.FirstOrDefault(x => x.BookID == book.BookID);
        if ( entity == null )
        {
          entity = new Book { DateCreated = now };
          ctx.Books.AddObject(entity);
        }
        else
          entity.DateModified = now;
        
        entity.ASIN = book.ASIN;
        ISBN isbn = null;
        if ( !string.IsNullOrEmpty(book.ISBN10) )
        {
          isbn = new ISBN10(book.ISBN10);
          entity.ISBN10 = isbn.ToString();
          entity.ISBN13 = new ISBN13(isbn.Transform()).ToString();
        }
        else
        {
          isbn = new ISBN13(book.ISBN13);
          entity.ISBN13 = isbn.ToString();
          entity.ISBN10 = new ISBN10(isbn.Transform()).ToString();
        }
        entity.DeweyDecimal = book.DeweyDecimal;
        entity.LCCN = book.LCCN;

        entity.Title = book.Title;
        entity.Subtitle = book.Subtitle;

        entity.LargeImageURL = book.LargeImageURL;
        entity.MediumImageURL = book.MediumImageURL;
        entity.SmallImageURL = book.SmallImageURL;

        entity.PublicationDate = book.PublicationDate;
        entity.NumberOfPages = book.NumberOfPages;

        entity.Edition = book.Edition;
        entity.EditorialReview = book.EditorialReview;

        entity.Path = book.Path;
        entity.FileName = book.FileName;

        #region set links

        if ( book.Links != null )
        {
          foreach ( var item in book.Links )
          {
            if ( book.Links.FirstOrDefault( x => x.Name == item.Name ) != null)
              continue;

            Link link = new Link() { DateCreated = now, Book = entity, Name = item.Name, Path = item.Path };
            entity.Links.Add(link);
          }
        }

        #endregion

        #region set publisher

        var publisher = ctx.Publishers.FirstOrDefault(x => x.Name == book.PublisherName);
        if ( publisher == null )
          publisher = new Publisher() { Name = book.PublisherName };

        entity.Publisher = publisher;

        #endregion

        #region set authors

        if ( book.Authors != null )
        {
          foreach ( var item in book.Authors )
          {
            var author = ctx.Authors.FirstOrDefault(x => x.Name == item.Name);
            if ( author == null )
              author = new Author() { Name = item.Name };

            ctx.BookAuthors.AddObject(new BookAuthor() { Author = author, Book = entity });
          }
        }

        #endregion

        #region set topics

        if ( book.Topics != null )
        {
          foreach ( var item in book.Topics )
          {
            var topic = ctx.Topics.FirstOrDefault(x => x.Name == item.Name);
            if ( topic == null )
              topic = new Topic() { Name = item.Name };

            ctx.BookTopics.AddObject(new BookTopic() { Topic = topic, Book = entity });
          }
        }

        #endregion

        ctx.SaveChanges();
      }        
    
    }


  }
}
